﻿package{
	import flash.display.Sprite;
	import flash.events.Event;
	import rob.core.World3d;
	import rob.core.Camera3d;
	import rob.core.Ini;
	import rob.entity.*;
	import rob.parser.ParserOBJ;
	import rob.ui.*;
	
	public class Root extends Sprite{
		// scene sprite made in IDE
		public var scene_mc:Sprite;
		public var overlay:Sprite;
		public var bounds:Sprite;
		
		private var _wrapper:Sprite;
		private var _scene:Sprite, _ground:Ground;
		private var _world:World3d;
		private var _camera:Camera3d;
		private var _input:UserInput;
		private var _parser:ParserOBJ;
		
		public function Root():void{
			scene_mc.visible = false;
			// parse 3d mesh files
			_parse3d();
			// wait until parsed before running setup
			addEventListener(Event.ENTER_FRAME,_waitForParsing);
		}
		
		private function _parse3d():void{
			_parser = ParserOBJ.instance;
			_parser.parsed = false;
			_parser.filenames = Ini.instance.filenames;
			_parser.loadMeshes();
		}
		
		private function _waitForParsing(evt:Event):void{
			if(_parser.parsed){
				_setup();
				removeEventListener(Event.ENTER_FRAME,_waitForParsing);
			}
			else trace("Waiting for parsing...");
		}
		
		private function _setup():void{
			try{
				_setupMovie();
				_setupWorld();
				_setupScene();
				_setupCamera();
				_setupBoundBoxes();
				_initSpriteScales();
				_setupUI();
				_world.initialise();
				addEventListener(Event.ENTER_FRAME,loop);
			}
			catch(e){
				trace("Failed:  " + e);
			}
		}
		
		private function loop(event:Event):void{
			_input.tick();
			_world.update();
		}
		
		private function _setupMovie(){
			// set quality
			this.stage.quality = Ini.instance.stageQuality;
			this.stage.frameRate = Ini.instance.frameRate;
			// create wrapper mc and center
			_wrapper = new Sprite();
			this.addChild(_wrapper);
			this.addChild(overlay);
			_wrapper.x = this.stage.stageWidth/2;
			_wrapper.y = this.stage.stageHeight/2;
			
		}
		
		// use _scene_mc to construct world
		private function _setupWorld():void{
			_world = World3d.instance;
			var numChildren:Number = scene_mc.numChildren;
			var child:Sprite, childString:String;
			var object:Object, props:Array;
			for(var i:Number = 0; i < numChildren; i++){
				child = scene_mc.getChildAt(i);
				childString = child.toString();
			// object types
				if(childString.search("b_") != -1){
					_world.addBuilding(new Building(child));
				}
				else if(childString.search("s_") != -1){
					_world.addStructure(new Structure(child));
				}				
				else if(childString.search("f_") != -1){
					_world.addFloor(new Floor(child));
				}
				else if(childString.search("c_") != -1){
					_world.addBot(new Bot(child));
				}
				else if(childString.search("v_") != -1){
					_world.addCar(new Car(child));
				}
				
			}
			// remove the 'helper mc' from display list
			this.removeChild(scene_mc);
		}
		
		// use _world to generate scene
		private function _setupScene():void{
			_scene = new Sprite();
			// ground is 0th child
			_scene.addChild(_world.ground.container);
			
			// add base bounding poly (replaces bsqr?)
			// add all building polys to _scene display list
			for each(b in _world.buildings){
				_world.ground.container.addChild(b.base);
				_world.ground.container.addChild(b.bsqr);
				for each(p in b.mesh.aPolygon) _scene.addChild(p);
			}
			// attach structure gfx and bases
			for each(s in _world.structures){
				_world.addFloor(s.baseHitTest);
				_scene.addChild(s.gfx);
			}
			// attach gfx in floor sprite to floor sprite
			for each(f in _world.ground.floor) f.addChild(f.gfx);
			// attach bot gfx
			for each(c in _world.bots) _scene.addChild(c.anim);
			// attach car gfx
			for each(v in _world.cars) _scene.addChild(v.anim);
			
			// display the scene and bind it to the world
			_wrapper.addChild(_scene);
			_world.scene = _scene;
		}
		
		private function _setupCamera():void{
			_camera = new Camera3d();
			_camera.sz = Ini.instance.sz;
			_camera.position = Ini.instance.cameraPos;
			_camera.lookAt(_world.origin);
			_world.camera = _camera;
		}
		
		private function _setupBoundBoxes():void{
			// set up bounding square
			// one must project mesh points first
			for each(b in _world.buildings){
				b.mesh.project(_camera);
				b.computeBSqr();
				b.drawBase();
			}
			// also set overall bounding sprite for stage
			_world.bounds = bounds;
		}
		
		// setup initial scalings: stage coords -> world coords
		// e.g. the further from camera the more scaled down it is
		private function _initSpriteScales():void{
			var k:Number =  _camera.sz / _camera.position.y;
			for each(var f:Floor in _world.ground.floor) f.setDimensions(k);
			for each(var b:Bot in _world.bots) b.setDimensions(k);
			for each(var s:Structure in _world.structures) s.setDimensions(_camera);
			for each(var v:Car in _world.cars) v.setDimensions(k);
		}
		
		private function _setupUI():void{
			_input = new UserInput(_world);						
			KeyController.init(this.stage); 
			MouseController.init(this.stage);
		}
	}
}